#include "Game.h"

#include "Input.h"
#include "GameObjectManager.h"
#include "Spawner.h"

#include "glut.h"
#include <GL/gl.h>
#include <iostream>
#include <time.h>

#include <cstdlib>

using namespace std;

Game* Game::game = 0;

Game* Game::getInstance()
{
	if (!game)
	{
		game = new Game();
	}
	return game;
}


void Game::destroyInstance()
{
	Input::destroyInstance();
	Spawner::destroyInstance();
	GameObjectManager::destroyInstance();

	delete game;
	game = 0;
}


void setColor(float r, float g, float b) { glColor3f(r,g,b); }


void mouse(int btn, int state, int x, int y) {
	// Mouse Manager
	/*
	if (state == GLUT_DOWN) {
		if (btn == GLUT_LEFT_BUTTON) // do something when left mouse button down
		else if (btn == GLUT_RIGHT_BUTTON) // do something when right mouse button down
		else // do something when other button down
	}
	*/	
}

void keyboard(unsigned char key, int x, int y) {
	// Regular Keyboard Manager
	Input::getInstance()->handleKeyPress(key);
}

void special(int key, int x, int y) {
	// Special Keyboard Manager
	Input::getInstance()->handleSpecialKeyPress(static_cast<char>(key));
}


void draw()
{	
	// Draw the scene
	glClear(GL_COLOR_BUFFER_BIT);
	//setColor(1.0,1.0,1.0);
	glMatrixMode(GL_MODELVIEW);

	// Update the game logic
	Game::getInstance()->update();
	
	// Draw the objects (walls, players, monsters, keys, doors, gate, rooms, gold bags, ...)
	Game::getInstance()->drawGame();

	glFlush();
	glutSwapBuffers();
}


bool Game::init(int argc, char **argv, const std::string& pName1, const std::string& pName2) {
	playerName1 = pName1;
	playerName2 = pName2;

	mapCount = argc - 1;
	mapNames.resize(mapCount);
	currentMap = 0;

	for (int i = 0; i < mapCount; i++)
		mapNames[i] = argv[i + 1];
	
	int currentMap = 0;

	// Get the name if the map.
	if (mapCount < 1)
	{
		std::cout << "No map file specified." << std::endl;
	}
	else
	{
		if (!loadMap(mapNames[currentMap].c_str()))
			return false;
	}

	// Initialization of the window
	glutInit(&argc, argv);
	// Size and position
	glutInitWindowSize(500, 500);
	glutInitWindowPosition(800, 50);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	// Name
	glutCreateWindow("Dungeon Adventure");
	// Managers
	glutMouseFunc(mouse);
	glutKeyboardFunc(keyboard);
	glutSpecialFunc(special);
	glutDisplayFunc(draw);
	glutIdleFunc(draw);
	// Point of view
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	float limitX = static_cast<float>(map.getWidth()) * 0.5f;
	float limitY = static_cast<float>(map.getHeight()) * 0.5f;
	glOrtho(-limitX,limitX,-limitY,limitY, -1.0, 1.0);
	glRotatef(180,1,0,0);
	glTranslatef(-limitX,-limitY,0.0);
	glMatrixMode(GL_MODELVIEW);

	// Anti-aliasing code here.
	glEnable (GL_LINE_SMOOTH);
	glEnable (GL_BLEND);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);

	glClearColor(0.0, 0.0, 0.0, 0.0);
	// Initialize randomizer
	srand((unsigned int)time(NULL));

	return true;
}


bool Game::loadMap(const char *mapName)
{
	map.clear();

	dungeonEnded = false;
	success = false;
	
	// Load the map and check if it succeeded.
	if (!map.loadFile(mapName, playerName1, playerName2))
	{
		std::cout << "Invalid map loaded: " << mapName << std::endl;
		std::cout << "Each map required at least a player, a room and a gate." << std::endl;
		map.clear();
		return false;
	}

	system("cls"); // Clears window of text.

	// Welcome message
	cout << "Welcome " << playerName1 << " and " << playerName2 << ", to the Dungeon Adventure" << endl;
	cout << "Your quest is to kill the monsters, loot any goods, and escape safely." << endl;

	return true;
}


void Game::playGame() 
{
	// Game loop is managed by the window
	glutMainLoop();
}


void Game::dungeonOver(const std::string& reason, bool win)
{
	// Display game over message.
	std::cout << reason << std::endl;
	
	dungeonEnded = true;
	success = win;
}


void Game::update()
{
	if (!dungeonEnded) // Normal game loop.
	{
		GameObjectManager::getInstance()->update();
		Input::getInstance()->reset();
	}
	else // Game ended for some reason.
	{
		if (!success) // Players failed to complete the dungeon.
		{
			std::cout << playerName1 << " and " << playerName2 << " failed the dungeon!" << std::endl;
			std::cout << "You can replay the dungeon if you wish." << std::endl;
			
			system("pause");

			loadMap(mapNames[currentMap].c_str());
		}
		else // Success!
		{
			currentMap++; // Prepare for loading the next map.

			if (currentMap < mapCount) // Load next map.
			{
				std::cout << "Get ready for the next dungeon!" << std::endl;

				system("pause");

				loadMap(mapNames[currentMap].c_str());
			}
			else // All maps completed.
			{
				std::cout << "Congratulations, you beat the game!" << std::endl;
				std::cout << "- GAME OVER -" << std::endl;
				
				system("pause");

				exit(0);
			}
		}
	}
}


void Game::drawGame() const
{
	map.draw();
}